#include "flash_if.h"

uint32_t GetSector(uint32_t Address);
unsigned char Erase_NbSectors; //要擦除的块数量

/////////////////////////////////////////////////////////////////////////////////

uint32_t FLASH_Read(uint32_t ReadAddress)
{
    return  *(uint32_t*)(ReadAddress);
}

/**
  * @brief  Unlocks Flash for write access
  * @param  None
  * @retval None
  */
void FLASH_If_Init(void)
{
    /* unlock the flash program erase controller */
    fmc_unlock();
    /* clear pending flags */
    fmc_flag_clear(FMC_FLAG_BANK0_END | FMC_FLAG_BANK0_WPERR | FMC_FLAG_BANK0_PGERR);
}

/**
  * @brief  This function does an erase of all user flash area
  * @param  StartSector: start of user flash area
  * @retval 0: user flash area successfully erased
  *         1: error occurred
  */
uint32_t FLASH_If_Erase(uint32_t address)
{
    if(address >= MAX_FLASH_ADDRESS){
       return 0;
    }
    else
    {
        /* unlock the flash program erase controller */
        fmc_unlock();
        /* clear pending flags */
        fmc_flag_clear(FMC_FLAG_BANK0_END | FMC_FLAG_BANK0_WPERR | FMC_FLAG_BANK0_PGERR);
        /* wait the erase operation complete*/
        if(FMC_READY != fmc_page_erase(address))
        {
           return 1;
        }
        /* lock the flash program erase controller */
        //fmc_lock();
    }
    return (0);
}

uint32_t FLASH_If_Erase_Sector(uint32_t StartSector,uint32_t fsize)
{
  return (0);
}

/**
  * @brief  This function writes a data buffer in flash (data are 32-bit aligned).
  * @note   After writing data buffer, the flash content is checked.
  * @param  FlashAddress: start address for writing data buffer
  * @param  Data: pointer on data buffer
  * @param  DataLength: length of data buffer (unit is 32-bit word)
  * @retval 0: Data successfully written to Flash memory
  *         1: Error occurred while writing data in Flash memory
  *         2: Written Data in flash memory is different from expected one
  */
uint32_t FLASH_If_Write(uint32_t FlashAddress, uint32_t* Data ,uint32_t DataLength)
{
  uint32_t i = 0;
  FLASH_If_Init();
  for (i = 0; (i < DataLength) && (FlashAddress <= (USER_FLASH_END_ADDRESS- 4 + 1)); i++)
  {
    /* Device voltage range supposed to be [2.7V to 3.6V], the operation will
       be done by word */
    if(fmc_word_program(FlashAddress, *(uint32_t*)(Data+i)) == FMC_READY)
    {
     /* Check the written value */
      if (*(uint32_t*)FlashAddress != *(uint32_t*)(Data+i))
      {
        /* Flash content doesn't match SRAM content */
        return(FLASHIF_WRITINGCTRL_ERROR);
      }
      /* Increment FLASH destination address */
      FlashAddress += 4;
    }
    else
    {
      /* Error occurred while writing data in Flash memory */
      return (FLASHIF_WRITING_ERROR);
    }
  }

  return (FLASHIF_OK);
}

/**
  * @brief  Returns the write protection status of user flash area.
  * @param  None
  * @retval 0: No write protected sectors inside the user flash area
  *         1: Some sectors inside the user flash area are write protected
  */
uint16_t FLASH_If_GetWriteProtectionStatus(void)
{
    return 0;
}

/**
  * @brief  Gets the page of a given address
  * @param  address: Flash address
  * @retval The sector of a given address
  */
uint16_t GetPage(uint32_t address)
{
    uint16_t page = 0;
    if(address < FMC_BANK0_END_ADDRESS)
        page = address / FMC_PAGE_SIZE_BANK0;
    else
        page = ((address - FMC_BANK0_END_ADDRESS - 1) / FMC_PAGE_SIZE_BANK1) + 256;
    return page;
}


/**
  * @brief  Configure the write protection status of user flash area.
  * @param  modifier DISABLE or ENABLE the protection
  * @retval HAL_StatusTypeDef HAL_OK if change is applied.
  */
HAL_StatusTypeDef FLASH_If_WriteProtectionConfig(uint32_t modifier)
{
    uint32_t wp_value = 0xFFFFFFFF,protected_pages = 0x0;
    __IO fmc_state_enum fmc_state = FMC_READY;
    wp_value = ob_write_protection_get();
    FLASH_If_Init();
    ob_unlock();
    if(!modifier)
    {
        /* Get pages already write protected */
        protected_pages = ~(wp_value | FLASH_SECTOR_TO_BE_PROTECTED);

        /* Check if desired pages are already write protected */
        if((wp_value | (~FLASH_SECTOR_TO_BE_PROTECTED)) != 0xFFFFFFFF ){
            /* Erase all the option Bytes */
            fmc_state = ob_erase();

            /* Check if there is write protected pages */
            if(protected_pages != 0x0){
                /* Restore write protected pages */
                fmc_state = ob_write_protection_enable(protected_pages);
            }
            /* Generate System Reset to load the new option byte values */
            //NVIC_SystemReset();
        }
    }
    else
    {
        /* Get current write protected pages and the new pages to be protected */
        protected_pages =  (~wp_value) | FLASH_SECTOR_TO_BE_PROTECTED;

        /* Check if desired pages are not yet write protected */
        if(((~wp_value) & FLASH_SECTOR_TO_BE_PROTECTED )!= FLASH_SECTOR_TO_BE_PROTECTED)
        {
            /* Erase all the option Bytes because if a program operation is
            performed on a protected page, the Flash memory returns a
            protection error */
            fmc_state = ob_erase();

            /* Enable the pages write protection */
            fmc_state = ob_write_protection_enable(protected_pages);

            /* Generate System Reset to load the new option byte values */
           // NVIC_SystemReset();
        }
    }
    ob_lock();
    fmc_lock();
    return HAL_OK;
}

